package impl

import (
	"adam2/internal/constants"
	"adam2/internal/dto"
	"adam2/internal/model"
	"adam2/internal/properties"
	pConstants "anubis-framework/pkg/constants"
	pDomain "anubis-framework/pkg/domain"
	"anubis-framework/pkg/util"
	"time"
)

type TrainingTransactionDataServiceImpl struct {
	*BaseServiceImpl
}

// 获取service的实现类
func GetTrainingTransactionDataServiceImpl() *TrainingTransactionDataServiceImpl {
	return &TrainingTransactionDataServiceImpl{GetBaseServiceImpl()}
}

// 根据trg_info_id，判断是否是持仓状态
func (_trainingTransactionDataServiceImpl TrainingTransactionDataServiceImpl) IsHoldingShareByTrainingName(trainingName string) *pDomain.ServiceResult {
	var status int = _trainingTransactionDataServiceImpl._trainingTransactionDataDaoImpl.IsHoldingShareByTrainingName(trainingName)
	var serviceResult *pDomain.ServiceResult = &pDomain.ServiceResult{}
	serviceResult.Code = pConstants.OPERATION_SUCCESS_CODE
	serviceResult.Message = pConstants.OPERATION_SUCCESS_MESSAGE
	serviceResult.Success = true
	serviceResult.Result = status
	return serviceResult
}

// 开多仓
func (_trainingTransactionDataServiceImpl TrainingTransactionDataServiceImpl) OpenLongPosition(trainingName string) *pDomain.ServiceResult {
	var trainingInfo model.TrainingInfo = _trainingTransactionDataServiceImpl._trainingInfoDaoImpl.FindByName(trainingName)
	var decryptCode, _ = util.Decrypt(trainingInfo.Code, properties.TrainingProperties_.EncryptKey, properties.TrainingProperties_.IV)
	var openLongPositionDate = util.DateToString(trainingInfo.EndDate)
	var commodityFutureDateData model.CommodityFutureDateData = _trainingTransactionDataServiceImpl._commodityFutureDateDataDaoImpl.FindByCodeAndTransactionDate(decryptCode, openLongPositionDate)
	//var stockTransactionDataDall model.StockTransactionDataAll = _trainingTransactionDataServiceImpl._stockTransactionDataAllDaoImpl.FindByCodeAndDate(decryptCode, openLongPositionDate)

	var trainingTransactionData model.TrainingTransactionData = model.TrainingTransactionData{}
	trainingTransactionData.Market = trainingInfo.Market
	trainingTransactionData.TrainingInfoId = trainingInfo.ID
	trainingTransactionData.Code = trainingInfo.Code
	trainingTransactionData.BuyDate = trainingInfo.EndDate
	trainingTransactionData.BuyPrice = commodityFutureDateData.ClosePrice
	trainingTransactionData.Direction = constants.BULL
	trainingTransactionData.CreateTime = time.Now()

	_trainingTransactionDataServiceImpl._trainingTransactionDataDaoImpl.Save(trainingTransactionData)

	var serviceResult *pDomain.ServiceResult = &pDomain.ServiceResult{}
	serviceResult.Code = pConstants.OPERATION_SUCCESS_CODE
	serviceResult.Message = pConstants.OPERATION_SUCCESS_MESSAGE
	serviceResult.Success = true
	return serviceResult
}

// 开空仓
func (_trainingTransactionDataServiceImpl TrainingTransactionDataServiceImpl) OpenShortPosition(trainingName string) *pDomain.ServiceResult {
	var trainingInfo model.TrainingInfo = _trainingTransactionDataServiceImpl._trainingInfoDaoImpl.FindByName(trainingName)
	var decryptCode, _ = util.Decrypt(trainingInfo.Code, properties.TrainingProperties_.EncryptKey, properties.TrainingProperties_.IV)
	var openShortPositionDate = util.DateToString(trainingInfo.EndDate)
	var commodityFutureDateData model.CommodityFutureDateData = _trainingTransactionDataServiceImpl._commodityFutureDateDataDaoImpl.FindByCodeAndTransactionDate(decryptCode, openShortPositionDate)

	var trainingTransactionData model.TrainingTransactionData = model.TrainingTransactionData{}
	trainingTransactionData.Market = trainingInfo.Market
	trainingTransactionData.TrainingInfoId = trainingInfo.ID
	trainingTransactionData.Code = trainingInfo.Code
	trainingTransactionData.SellDate = trainingInfo.EndDate
	trainingTransactionData.SellPrice = commodityFutureDateData.ClosePrice
	trainingTransactionData.Direction = constants.SHORT
	trainingTransactionData.CreateTime = time.Now()

	_trainingTransactionDataServiceImpl._trainingTransactionDataDaoImpl.Save(trainingTransactionData)

	var serviceResult *pDomain.ServiceResult = &pDomain.ServiceResult{}
	serviceResult.Code = pConstants.OPERATION_SUCCESS_CODE
	serviceResult.Message = pConstants.OPERATION_SUCCESS_MESSAGE
	serviceResult.Success = true
	return serviceResult
}

// 平多仓
func (_trainingTransactionDataServiceImpl TrainingTransactionDataServiceImpl) CloseLongPosition(trainingName string) *pDomain.ServiceResult {
	// 查询平多仓时的数据
	var trainingInfo model.TrainingInfo = _trainingTransactionDataServiceImpl._trainingInfoDaoImpl.FindByName(trainingName)
	var decryptCode, _ = util.Decrypt(trainingInfo.Code, properties.TrainingProperties_.EncryptKey, properties.TrainingProperties_.IV)
	var closeLongPositionDate = util.DateToString(trainingInfo.EndDate)
	var commodityFutureDateData model.CommodityFutureDateData = _trainingTransactionDataServiceImpl._commodityFutureDateDataDaoImpl.FindByCodeAndTransactionDate(decryptCode, closeLongPositionDate)

	// 查询开多仓时的数据
	var trainingTransactionData model.TrainingTransactionData = _trainingTransactionDataServiceImpl._trainingTransactionDataDaoImpl.FindByTrainingInfoIdAndSellDateNull(trainingInfo.ID)
	var profitAndLoss float64 = commodityFutureDateData.ClosePrice - trainingTransactionData.BuyPrice
	var profitAndLossRate float64 = (commodityFutureDateData.ClosePrice - trainingTransactionData.BuyPrice) / trainingTransactionData.BuyPrice * 100
	var _endDate string = util.DateToString(trainingInfo.EndDate)

	_trainingTransactionDataServiceImpl._trainingTransactionDataDaoImpl.UpdateSellDateAndSellPriceAndProfitAndLossRateById(trainingTransactionData.ID, _endDate, commodityFutureDateData.ClosePrice, profitAndLoss, profitAndLossRate)

	var serviceResult *pDomain.ServiceResult = &pDomain.ServiceResult{}
	serviceResult.Code = pConstants.OPERATION_SUCCESS_CODE
	serviceResult.Message = pConstants.OPERATION_SUCCESS_MESSAGE
	serviceResult.Success = true
	return serviceResult
}

// 平空仓
func (_trainingTransactionDataServiceImpl TrainingTransactionDataServiceImpl) CloseShortPosition(trainingName string) *pDomain.ServiceResult {
	// 查询平空仓时的数据
	var trainingInfo model.TrainingInfo = _trainingTransactionDataServiceImpl._trainingInfoDaoImpl.FindByName(trainingName)
	var decryptCode, _ = util.Decrypt(trainingInfo.Code, properties.TrainingProperties_.EncryptKey, properties.TrainingProperties_.IV)
	var closeShortPositionDate = util.DateToString(trainingInfo.EndDate)
	var commodityFutureDateData model.CommodityFutureDateData = _trainingTransactionDataServiceImpl._commodityFutureDateDataDaoImpl.FindByCodeAndTransactionDate(decryptCode, closeShortPositionDate)

	// 查询开空仓时的数据
	var trainingTransactionData model.TrainingTransactionData = _trainingTransactionDataServiceImpl._trainingTransactionDataDaoImpl.FindByTrainingInfoIdAndBuyDateNull(trainingInfo.ID)
	var profitAndLoss float64 = trainingTransactionData.SellPrice - commodityFutureDateData.ClosePrice
	var profitAndLossRate float64 = (trainingTransactionData.SellPrice - commodityFutureDateData.ClosePrice) / trainingTransactionData.SellPrice * 100
	var _endDate string = util.DateToString(trainingInfo.EndDate)

	_trainingTransactionDataServiceImpl._trainingTransactionDataDaoImpl.UpdateBuyDateAndBuyPriceAndProfitAndLossRateById(trainingTransactionData.ID, _endDate, commodityFutureDateData.ClosePrice, profitAndLoss, profitAndLossRate)

	var serviceResult *pDomain.ServiceResult = &pDomain.ServiceResult{}
	serviceResult.Code = pConstants.OPERATION_SUCCESS_CODE
	serviceResult.Message = pConstants.OPERATION_SUCCESS_MESSAGE
	serviceResult.Success = true
	return serviceResult
}

// 买入
func (_trainingTransactionDataServiceImpl TrainingTransactionDataServiceImpl) Buy(trainingName string) *pDomain.ServiceResult {
	var trainingInfo model.TrainingInfo = _trainingTransactionDataServiceImpl._trainingInfoDaoImpl.FindByName(trainingName)
	var decryptCode, _ = util.Decrypt(trainingInfo.Code, properties.TrainingProperties_.EncryptKey, properties.TrainingProperties_.IV)
	var buyDate = util.DateToString(trainingInfo.EndDate)
	var stockTransactionDataDall model.StockTransactionDataAll = _trainingTransactionDataServiceImpl._stockTransactionDataAllDaoImpl.FindByCodeAndDate(decryptCode, buyDate)

	var trainingTransactionData model.TrainingTransactionData = model.TrainingTransactionData{}
	trainingTransactionData.Market = trainingInfo.Market
	trainingTransactionData.TrainingInfoId = trainingInfo.ID
	trainingTransactionData.Code = trainingInfo.Code
	trainingTransactionData.BuyDate = trainingInfo.EndDate
	trainingTransactionData.BuyPrice = stockTransactionDataDall.ClosePrice
	trainingTransactionData.Direction = constants.BULL
	trainingTransactionData.CreateTime = time.Now()

	_trainingTransactionDataServiceImpl._trainingTransactionDataDaoImpl.Save(trainingTransactionData)

	var serviceResult *pDomain.ServiceResult = &pDomain.ServiceResult{}
	serviceResult.Code = pConstants.OPERATION_SUCCESS_CODE
	serviceResult.Message = pConstants.OPERATION_SUCCESS_MESSAGE
	serviceResult.Success = true
	return serviceResult
}

// 卖出
func (_trainingTransactionDataServiceImpl TrainingTransactionDataServiceImpl) Sell(trainingName string) *pDomain.ServiceResult {
	// 查询卖出时的数据
	var trainingInfo model.TrainingInfo = _trainingTransactionDataServiceImpl._trainingInfoDaoImpl.FindByName(trainingName)
	var decryptCode, _ = util.Decrypt(trainingInfo.Code, properties.TrainingProperties_.EncryptKey, properties.TrainingProperties_.IV)
	var sellDate = util.DateToString(trainingInfo.EndDate)
	var stockTransactionDataDall model.StockTransactionDataAll = _trainingTransactionDataServiceImpl._stockTransactionDataAllDaoImpl.FindByCodeAndDate(decryptCode, sellDate)

	// 查询买入时的数据
	var trainingTransactionData model.TrainingTransactionData = _trainingTransactionDataServiceImpl._trainingTransactionDataDaoImpl.FindByTrainingInfoIdAndSellDateNull(trainingInfo.ID)
	var profitAndLoss float64 = stockTransactionDataDall.ClosePrice - trainingTransactionData.BuyPrice
	var profitAndLossRate float64 = (stockTransactionDataDall.ClosePrice - trainingTransactionData.BuyPrice) / trainingTransactionData.BuyPrice * 100
	var _endDate string = util.DateToString(trainingInfo.EndDate)

	_trainingTransactionDataServiceImpl._trainingTransactionDataDaoImpl.UpdateSellDateAndSellPriceAndProfitAndLossRateById(trainingTransactionData.ID, _endDate, stockTransactionDataDall.ClosePrice, profitAndLoss, profitAndLossRate)

	var serviceResult *pDomain.ServiceResult = &pDomain.ServiceResult{}
	serviceResult.Code = pConstants.OPERATION_SUCCESS_CODE
	serviceResult.Message = pConstants.OPERATION_SUCCESS_MESSAGE
	serviceResult.Success = true
	return serviceResult
}

// 计算收益率
func (_trainingTransactionDataServiceImpl TrainingTransactionDataServiceImpl) CalculateProfitAndLossRate(trainingName string) *pDomain.ServiceResult {
	var trainingInfo model.TrainingInfo = _trainingTransactionDataServiceImpl._trainingInfoDaoImpl.FindByName(trainingName)
	var trainingTransactionDataArray model.TrainingTransactionDataArray = _trainingTransactionDataServiceImpl._trainingTransactionDataDaoImpl.FindByTrainingInfoIdAndBuyDateNotNullAndSellDateNotNullOderByBuyDateAsc(trainingInfo.ID)

	var profitAndLossRate float64 = 100
	for _, trainingTransactionData := range trainingTransactionDataArray {
		profitAndLossRate = profitAndLossRate * (1 + trainingTransactionData.ProfitAndLossRate/100)
	}

	var serviceResult *pDomain.ServiceResult = &pDomain.ServiceResult{}
	serviceResult.Code = pConstants.OPERATION_SUCCESS_CODE
	serviceResult.Message = pConstants.OPERATION_SUCCESS_MESSAGE
	serviceResult.Result = profitAndLossRate
	serviceResult.Success = true
	return serviceResult
}

// 返回收益率折线图数据
func (_trainingTransactionDataServiceImpl TrainingTransactionDataServiceImpl) FindProfitAndLossRatePictureData(trainingName string) *pDomain.ServiceResult {
	var trainingTransactionDataArray model.TrainingTransactionDataArray = _trainingTransactionDataServiceImpl._trainingTransactionDataDaoImpl.JoinTrainingInfoByTrainingInfoNameOrderByBeginDateAsc(trainingName)
	var trainingInfo model.TrainingInfo = _trainingTransactionDataServiceImpl._trainingInfoDaoImpl.FindByName(trainingName)
	var decryptCode, _ = util.Decrypt(trainingInfo.Code, properties.TrainingProperties_.EncryptKey, properties.TrainingProperties_.IV)
	var _beginDate string = util.DateToString(trainingInfo.BeginDate)
	var _endDate string = util.DateToString(trainingInfo.EndDate)

	// 收益率
	var profitAndLossRateArray []float64
	// 日期
	var dateArray []string
	var profitAndLossRatePictureDto dto.ProfitAndLossRatePictureDto = dto.ProfitAndLossRatePictureDto{}

	// 股票
	if trainingInfo.Market == constants.STOCK_MARKET {
		var stockTransactionDataAllArray model.StockTransactionDataAllArray = _trainingTransactionDataServiceImpl._stockTransactionDataAllDaoImpl.FindByCodeBetweenDateOrderByDateAsc(decryptCode, _beginDate, _endDate)
		// 上一次的收益率
		var lastProfitAndLossRate float64
		var profitAndLossRate float64 = 100
		var index int = 0
		for _, stockTransactionData := range stockTransactionDataAllArray {
			if index > len(trainingTransactionDataArray)-1 {
				break
			}
			if stockTransactionData.Date.Equal(trainingTransactionDataArray[index].SellDate) {
				profitAndLossRate = profitAndLossRate * (1 + trainingTransactionDataArray[index].ProfitAndLossRate/100)
				profitAndLossRateArray = append(profitAndLossRateArray, profitAndLossRate)
				lastProfitAndLossRate = profitAndLossRate
				index++
			} else {
				if len(profitAndLossRateArray) != 0 {
					profitAndLossRateArray = append(profitAndLossRateArray, lastProfitAndLossRate)
					lastProfitAndLossRate = profitAndLossRate
				}
			}
			if len(profitAndLossRateArray) != 0 && index <= len(trainingTransactionDataArray)-1 {
				var _date = util.DateToString(stockTransactionData.Date)
				dateArray = append(dateArray, _date)
			}
		}
	}
	// 期货
	if trainingInfo.Market == constants.COMMODITY_FUTURE_MARKET {
		var commodityFutureDateDataArray model.CommodityFutureDateDataArray = _trainingTransactionDataServiceImpl._commodityFutureDateDataDaoImpl.FindByCodeBetweenDateOrderByDateAsc(decryptCode, _beginDate, _endDate)
		// 上一次的收益率
		var lastProfitAndLossRate float64
		var profitAndLossRate float64 = 100
		var index int = 0
		for _, commodityFutureDateData := range commodityFutureDateDataArray {
			if index > len(trainingTransactionDataArray)-1 {
				break
			}
			if (trainingTransactionDataArray[index].Direction == constants.BULL && commodityFutureDateData.TransactionDate.Equal(trainingTransactionDataArray[index].SellDate)) ||
				(trainingTransactionDataArray[index].Direction == constants.SHORT && commodityFutureDateData.TransactionDate.Equal(trainingTransactionDataArray[index].BuyDate)) {
				profitAndLossRate = profitAndLossRate * (1 + trainingTransactionDataArray[index].ProfitAndLossRate/100)
				profitAndLossRateArray = append(profitAndLossRateArray, profitAndLossRate)
				lastProfitAndLossRate = profitAndLossRate
				index++
			} else {
				if len(profitAndLossRateArray) != 0 {
					profitAndLossRateArray = append(profitAndLossRateArray, lastProfitAndLossRate)
					lastProfitAndLossRate = profitAndLossRate
				}
			}
			if len(profitAndLossRateArray) != 0 && index <= len(trainingTransactionDataArray)-1 {
				var _date = util.DateToString(commodityFutureDateData.TransactionDate)
				dateArray = append(dateArray, _date)
			}
		}
	}

	profitAndLossRatePictureDto.ProfitAndLossRateArray = profitAndLossRateArray
	profitAndLossRatePictureDto.DateArray = dateArray
	var serviceResult *pDomain.ServiceResult = &pDomain.ServiceResult{}
	serviceResult.Code = pConstants.OPERATION_SUCCESS_CODE
	serviceResult.Message = pConstants.OPERATION_SUCCESS_MESSAGE
	serviceResult.Result = profitAndLossRatePictureDto
	serviceResult.Success = true
	return serviceResult
}
